package gwtupload.client.dnd;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.user.client.ui.FormPanel;
import com.google.gwt.user.client.ui.HasWidgets;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.xhr.client.XMLHttpRequest;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import gwtupload.client.Uploader;
import gwtupload.client.FileList;
import gwtupload.client.IFileInput;
/**
* DragAndDropFormPanel.
*
* @author Sultan Tezadov
* @author Manolo Carrasco MoƱino
*/
public class DragAndDropFormPanel extends FormPanel {
@Override
public void setAction(String url) {
super.setAction(url);
}
@Override
public void setEncoding(String encodingType) {
super.setEncoding(encodingType);
}
@Override
public void setMethod(String method) {
super.setMethod(method);
}
@Override
public HandlerRegistration addSubmitHandler(SubmitHandler handler) {
return super.addSubmitHandler(handler);
}
@Override
public HandlerRegistration addSubmitCompleteHandler(SubmitCompleteHandler handler) {
return super.addSubmitCompleteHandler(handler);
}
@Override
public void add(Widget w) {
super.add(w);
}
@Override
public void clear() {
super.clear();
}
@Override
public Iterator<Widget> iterator() {
return super.iterator();
}
@Override
public boolean remove(Widget w) {
return super.remove(w);
}
@Override
public void reset() {
super.reset();
}
@Override
public void submit() {
final List<IFileInput> childFileInputs = getChildFileInputs();
if (childFileInputs == null || childFileInputs.isEmpty()) {
return;
}
final ArrayList<IDragAndDropFileInput> dndFileInputs = new ArrayList<IDragAndDropFileInput>();
boolean thereAreNonDragAndDropFileInputs = false;
for (IFileInput fileInput : childFileInputs) {
if (fileInput instanceof IDragAndDropFileInput) {
final IDragAndDropFileInput dndFileInput = (IDragAndDropFileInput) fileInput;
if (dndFileInput.hasFiles()) {
dndFileInputs.add(dndFileInput);
} else {
// files might be selected via file dialog
thereAreNonDragAndDropFileInputs = true;
}
} else {
// files are selected via file dialog
thereAreNonDragAndDropFileInputs = true;
}
}
if (thereAreNonDragAndDropFileInputs) {
super.submit(); // submit non-dnd file inputs
}
if (!dndFileInputs.isEmpty()) {
submitDragAndDropFileInputs(dndFileInputs); // submit dnd file inputs
}
}
private static DragAndDropFormPanel currentInstance = null;
private XMLHttpRequest request = null;
private void submitDragAndDropFileInputs(ArrayList<IDragAndDropFileInput> dndFileInputs) {
// Fire the onSubmit event, because javascript's form.submit() does not
// fire the built-in onsubmit event.
if (!fireSubmitEvent()) {
return;
}
if (currentInstance != null) {
Uploader.log("DnD panel already sending files. ", null);
return;
}
for (IDragAndDropFileInput fileInput : dndFileInputs) {
final FileList files = fileInput.getFiles();
if (files != null && files.getLength() > 0) {
fileInput.lock();
currentInstance = this;
request = jsSubmit(getAction(), getMethod(), fileInput.getName(), files, dndFileInputs);
}
}
}
/**
* Fire a {@link FormPanel.SubmitEvent}.
*
* @return true to continue, false if canceled
*/
private boolean fireSubmitEvent() {
FormPanel.SubmitEvent event = new FormPanel.SubmitEvent();
fireEvent(event);
return !event.isCanceled();
}
private List<IFileInput> getChildFileInputs() {
final List<IFileInput> res = new ArrayList<IFileInput>();
findChildFileInputs(res, iterator());
return res;
}
private void findChildFileInputs(List<IFileInput> result, Iterator<Widget> iterator) {
if (result == null || iterator == null) {
return;
}
while (iterator.hasNext()) {
final Widget next = iterator.next();
if (next instanceof IFileInput) {
result.add((IFileInput) next);
} else if (next instanceof HasWidgets) {
// recursive call:
findChildFileInputs(result, ((HasWidgets) next).iterator());
}
}
}
// FIXME(manolo): Use session and reuse gwt form panel
private native XMLHttpRequest jsSubmit(String action, String method, String fieldName, FileList files, ArrayList<IDragAndDropFileInput> inputs) /*-{
var formData = new FormData();
for (var i = 0; i < files.length; i++) {
formData.append(fieldName, files[i]);
}
var request = new XMLHttpRequest();
var outerThis = this;
request.onreadystatechange = function() {
if (request.readyState == 4) { // the request has completed
outerThis.@gwtupload.client.dnd.DragAndDropFormPanel::onSubmitComplete(*)(request.responseText, request.status, inputs);
}
};
request.open(method, action);
request.send(formData);
return request;
}-*/;
// This is invoked from jsSubmit():
private void onSubmitComplete(String resultsHtml, int status, ArrayList<IDragAndDropFileInput> dndFileInputs) {
currentInstance = null;
if (dndFileInputs != null) {
for (IDragAndDropFileInput fileInput : dndFileInputs) {
fileInput.reset();
}
}
fireEvent(new SubmitCompleteEvent(resultsHtml) {
});
}
protected static void abortIfRunning() {
currentInstance = null;
// if (currentInstance != null) {
// currentInstance.request.abort();
// currentInstance.onSubmitComplete(null, 0, null);
// }
}
}